package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.CurrentUserHolder;
import com.nineclock.system.feign.SysOrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    private AttendGroupMapper attendGroupMapper;
    @Autowired
    private SysOrganizationFeign organizationFeign;
    @Autowired
    private AttendGroupPartMapper attendGroupPartMapper;


    /**
     * 分页查询考勤分页数据，业务实现基本步骤如下：
     * 1. 查询当前企业是否初次使用
     * 2. 如果初次使用需要新增默认考勤组, 设置企业所有部门员工都采用默认考勤组 (调用系统微服务获取企业所有部门)
     * 3. 分页查询企业考勤组列表数据
     * 4. 遍历列表，获取企业考勤组中参与者数量
     *
     * 在第2步骤中, 需要根据查询当前企业下部门ID集合，用于将默认考勤组关联到部门。故需要在系统微服务中提供Feign接口逻辑为根据企业ID查询企业部门ID集合。
     * 在第4步骤中, 需要计算考勤组下关联的用户数量，故还需要提供根据部门ID查询部门员工数量的接口。
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {

        //查询当前企业是否初次使用
        LambdaQueryWrapper<AttendGroup> attendGroupWrapper = new LambdaQueryWrapper<>();
        attendGroupWrapper.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());

        Integer count = attendGroupMapper.selectCount(attendGroupWrapper);

        //如果初次使用需要新增默认考勤组
        if(count == 0){
            AttendGroup attendGroup = new AttendGroup();
            attendGroup.setName("默认考勤组");
            attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
            attendGroup.setAddressRange(400);
            attendGroup.setAllowLateMinutes(10);
            attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
            attendGroup.setCreateTime(new Date());
            attendGroup.setLat(new Double("108.88995700000000000000"));
            attendGroup.setLng(new Double("34.37182600000000000000"));
            attendGroup.setStartWorkTime("09:00:00");
            attendGroup.setOffWorkTime("18:00:00");
            attendGroup.setStartNoonRestTime("12:00:00");
            attendGroup.setEndNoonRestTime("14:00:00");
            attendGroup.setLateMinutes(30);
            attendGroup.setWorkdays("1,1,1,1,1,0,0");
            attendGroupMapper.insert(attendGroup);

            //保存了默认的考勤组之后, 还需要设置所有的部门都采用该默认考勤组
            List<Long> ids = organizationFeign.queryDepartmentIds().getData();

            for (Long departmentId : ids) {
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectId(departmentId);
                attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
                attendGroupPart.setObjectType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                attendGroupPartMapper.insert(attendGroupPart);
            }
        }


        //2.根据企业ID 查询企业下考勤组中员工数量
        //2.1 查询考勤组分页 计算部门下员工数量  关联的用户数量
        Page<AttendGroup> p = new Page<>();
        p = attendGroupMapper.selectPage(p, attendGroupWrapper);
        List<AttendGroup> records = p.getRecords();

        List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);

        //遍历考勤组数据, 获取考勤组下关联的部门、员工, 并统计数量
        attendGroupDTOS.forEach(attendGroupDTO -> {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartWrapper = new LambdaQueryWrapper<>();
            attendGroupPartWrapper.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());
            attendGroupPartWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());

            List<AttendGroupPart> parts = attendGroupPartMapper.selectList(attendGroupPartWrapper);

            //获取参与者为部门ID集合
            List<Long> departmentIds = parts.stream().filter(attendGroupPart -> {
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_DEP.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            //获取参与者为用户ID集合
            List<Long> userIds = parts.stream().filter(attendGroupPart -> {
                return attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_USER.value();
            }).map(attendGroupPart -> {
                return attendGroupPart.getObjectId();
            }).collect(Collectors.toList());

            //统计关联的部门集合下的员工数量
            Integer depMemberCount=0;
            if(CollectionUtil.isNotEmpty(departmentIds)) {
                depMemberCount = organizationFeign.queryUserCountByDepartmentId(departmentIds).getData();
            }

            //总数量为 部门下的员工数量 + 员工ID集合大小
            Integer totalCount = depMemberCount + userIds.size();

            attendGroupDTO.setMemberNum(totalCount);
        });
        return new PageResult<AttendGroupDTO>(p.getTotal(), p.getPages(), attendGroupDTOS);
    }


    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
//        健壮性判断
        if (attendGroupDTO==null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);

//        设置考勤组管联的企业Id
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyUserId());

         //工作日, 使用逗号 "," 分割
        if (attendGroupDTO.getWorkdays()!=null){
            attendGroup.setWorkdays(StrUtil.join(",",attendGroupDTO.getWorkdays().toArray()));
        }

//        /必须/不用打卡的日期 ----> 获取出来之后使用逗号","拼接
        List<String> necessaryTimeList = new ArrayList<>();
        List<String> unnecessaryTimeList = new ArrayList<>();

        List<AttendGroupPCExtraConfigDTO> extraConfig=attendGroupDTO.getExtraConfig();
        for (AttendGroupPCExtraConfigDTO extraConfigDTO : extraConfig) {
            String date = extraConfigDTO.getSetDate();
            DateUtil.format(new Date(Long.parseLong(date)),"yyyy-MM-dd");

            if(extraConfigDTO.getRequiredAttend() == 1){
                necessaryTimeList.add(date);
            }else if(extraConfigDTO.getRequiredAttend() == 0){
                unnecessaryTimeList.add(date);
            }
        }

        attendGroup.setNecessaryTimeList(StrUtil.join(",",necessaryTimeList.toArray()));
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",",unnecessaryTimeList.toArray()));

        attendGroupMapper.insert(attendGroup);

//        关联用户、部门到该考勤组

//        需要参加考勤组的处理
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
//          删除用户与考勤组的处理
        participates.forEach(attendGroupPartDTO -> {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getObjectType, attendGroupPartDTO.getObjectType());
            attendGroupPartQw.eq(AttendGroupPart::getObjectId, attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.delete(attendGroupPartQw);

            //删除后添加新的关系
            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(attendGroup.getId());
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
            attendGroupPart.setObjectType(attendGroupPartDTO.getObjectType());
            attendGroupPart.setObjectId(attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.insert(attendGroupPart);
        });

//        不需要参与考勤组的处理
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
//          删除用户与考勤组的处理
        notParticipates.forEach(attendGroupPartDTO -> {
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getObjectType, attendGroupPartDTO.getObjectType());
            attendGroupPartQw.eq(AttendGroupPart::getObjectId, attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.delete(attendGroupPartQw);

            //删除后添加新的关系
            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setAttendGroupId(attendGroup.getId());
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_NO.value());
            attendGroupPart.setObjectType(attendGroupPartDTO.getObjectType());
            attendGroupPart.setObjectId(attendGroupPartDTO.getObjectId());

            attendGroupPartMapper.insert(attendGroupPart);
        });
    }


    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();

        LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());
        wrapper.eq(AttendGroupPart::getObjectId, companyUserId);

        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(wrapper);

        if (attendGroupPart==null){
            List<Long> departmentsByUserId = organizationFeign.queryDepartmentsByUserId(companyUserId).getData();
            if (CollectionUtil.isNotEmpty(departmentsByUserId)){
                for (Long aLong : departmentsByUserId) {
                    LambdaQueryWrapper<AttendGroupPart> qwrapper = new LambdaQueryWrapper<>();
                    qwrapper.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());
                    qwrapper.eq(AttendGroupPart::getObjectId, aLong);

                    attendGroupPart = attendGroupPartMapper.selectOne(qwrapper);
                    if (attendGroupPart!=null){
                        break;
                    }
                }
            }
        }

        if (attendGroupPart!=null){
            AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupPart.getAttendGroupId());
            AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);

            String workdays = attendGroup.getWorkdays();
            String[] split = workdays.split(",");
            List<String> list = Arrays.asList(split);

            attendGroupDTO.setWorkdays(list);

            return attendGroupDTO;
        }
        return null;
    }
}
